/**
 * MIT License
 * 
 * Copyright (c) 2024 - present @ ebraid
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <types.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>


/**
 * @brief Convert uppercase characters to lowercase characters
 * @param c: Character to convert
 * @return Lowercase character
 */
static int __tolower(int c)
{
    if (c >= 'A' && c <= 'Z') {
        return c + ('a' - 'A');
    }
    return c;
}


/**
 * @brief Convert a string to a long integer
 * @param str: String to convert
 * @param endptr: Pointer to the end of the string
 * @param base: Base of the number
 * @return Long integer
 */
long strtol(const char *str, char **endptr, int base)
{
    const char *p = str;
    long result = 0;
    int sign = 1;

    while (*p == ' ') {
        p++;
    }

    if (*p == '+') {
        p++;
    } else if (*p == '-') {
        sign = -1;
        p++;
    }

    if (base == 0) {
        if (*p == '0') {
            if (p[1] == 'x' || p[1] == 'X') {
                base = 16;
                p += 2;
            } else {
                base = 8;
                p++;
            }
        } else {
            base = 10;
        }
    }

    while (*p) {
        int digit;
        if (*p >= '0' && *p <= '9') {
            digit = *p - '0';
        } else if (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) {
            digit = __tolower(*p) - 'a' + 10;
        } else {
            break;
        }

        if (digit >= base) {
            break;
        }

        if (result > (LONG_MAX - digit) / base) {
            result = (sign == 1) ? LONG_MAX : LONG_MIN;
            break;
        }

        result = result * base + digit;
        p++;
    }

    if (endptr != NULL) {
        *endptr = (char *)p;
    }

    return result * sign;
}
